package com.jolink.omiis.wechat.message;

import java.io.StringReader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.google.gson.JsonObject;
import com.jolink.omiis.wechat.message.type.InfoType;
import com.jolink.omiis.wechat.outer.WeChatResponse;
import com.jolink.omiis.wechat.redis.IRedisProcessor;
import com.jolink.omiis.wechat.token.ComponentAccessTokenObservable;
import com.jolink.omiis.wechat.token.ComponentVerifyTicket;
import com.jolink.omiis.wechat.util.GsonUtil;
import com.jolink.omiis.wechat.util.XmlParser;

/**
 * 处理 Authorized、Ticket等信息Handler
 * 
 * @author WangYanqing
 *
 */

@Component
public class AuthorityMessageHandler extends AbstractMessageHandler implements IMessageHandler {

	public AuthorityMessageHandler() {
	}

	private static Logger logger = LoggerFactory.getLogger(AuthorityMessageHandler.class);

	@Override
	public WeChatResponse handleMessage() throws Exception {
		long t1 = System.currentTimeMillis();
		logger.info("开始处理授权请求......");
		WeChatResponse wr = createDefaultWeChatResponse();
		wr.setResponseMsg("success");
		try {
			Document doc = XmlParser.str2Xml(getReqMessage());
			Element infoTypeE = (Element) doc.selectSingleNode("/xml/InfoType");
			Element appIdE = (Element) doc.selectSingleNode("/xml/AppId");
			String appId = appIdE.getTextTrim();
			logger.info("接收到的消息开放平台ID：{}，开放平台标识：{}。", appId, getContext().getCompentInfo().get("app_id"));
			if (!appId.equals(getContext().getCompentInfo().get("app_id"))) {
				logger.info("接收到其他三方平台消息！");
				return wr;
			}
			String value = infoTypeE.getTextTrim();
			logger.info("接收到授权通知类型，InfoType：{}。", value);
			InfoType infoType = InfoType.valueOf(value.toUpperCase());
			boolean isReleaseTest = getContext().getServiceUtil().getConfiguration()
					.getBoolean("OMIIS_IS_RELEASE_TEST");
			try {
				switch (infoType) {
				case COMPONENT_VERIFY_TICKET:
					processComponentVerifyTicket(getReqMessage());
					break;
				case AUTHORIZED:
					if (isReleaseTest) {
						logger.info("进行全网测试授权，授权信息内容：{}。", doc.asXML());
						String authorizerAppid = doc.selectSingleNode("/xml/AuthorizerAppid").getText();
						String authorizationCode = doc.selectSingleNode("/xml/AuthorizationCode").getText();
						String authorizationCodeExpiredTime = doc.selectSingleNode("/xml/AuthorizationCodeExpiredTime")
								.getText();
						IRedisProcessor redis = getContext().getServiceUtil().getRedisProcessor();
						Map<String, String> authAppInfo = new HashMap<>();
						authAppInfo.put("authorizerAppid", authorizerAppid);
						authAppInfo.put("authorizationCode", authorizationCode);
						String component_access_token = getContext().getCompentInfo().get("component_access_token");
						String component_appid = getContext().getCompentInfo().get("app_id");
						String uri = COMPONENT_API_QUERY_AUTH;// "https://api.weixin.qq.com/cgi-bin/component/api_query_auth";
						Map<String, String> reqParams = new HashMap<String, String>();
						reqParams.put("component_access_token", component_access_token);
						JsonObject postData = new JsonObject();
						postData.addProperty("component_appid", component_appid);
						postData.addProperty("authorization_code", authorizationCode);
						logger.info("全网发布，获取授权码，请求信息：{}。", postData.toString());
						String result = (String) executePost(uri, reqParams, postData.toString());
						logger.info("全网发布测试，返回结果：{}。", result);
						JsonObject resultJson = GsonUtil.json2JsonObject(result);
						JsonObject authorization_info = resultJson.getAsJsonObject("authorization_info");
						String authorizer_access_token = authorization_info
								.getAsJsonPrimitive("authorizer_access_token").getAsString();
						String authorizer_refresh_token = authorization_info
								.getAsJsonPrimitive("authorizer_access_token").getAsString();
						authAppInfo.put("authorizationCodeExpiredTime", authorizationCodeExpiredTime);
						authAppInfo.put("authorizer_access_token", authorizer_access_token);
						authAppInfo.put("authorizer_refresh_token", authorizer_refresh_token);
						String authAppKey = "gzh_app_info_" + authorizerAppid;
						redis.hmset(authAppKey, authAppInfo);
						logger.info("将全网发布授权信息存入Redis成功。");
					} else {
						getContext().reloadWechatComponentInfo();
					}
					break;
				case UNAUTHORIZED:
					break;
				default:
					throw new RuntimeException("暂不支持的消息类型！");
				}
			} catch (Exception e2) {
				throw new RuntimeException(e2.getMessage(), e2);
			}
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage(), e);
		}

		long t2 = System.currentTimeMillis();
		logger.info("授权请求处理完成，耗时{}毫秒。", (t2 - t1));
		return wr;
	}

	@SuppressWarnings("unused")
	private void processAuthorized() {
	}

	/**
	 * 处理 Ticket，目前使用同步的更新操作，可以保证5s 内处理完成 token 的刷新操作，后续是否异步？
	 * 
	 * @param decrypt
	 *            消息明文（解密后）
	 */
	@SuppressWarnings("unchecked")
	private void processComponentVerifyTicket(String decrypt) {
		long t1 = System.currentTimeMillis();
		logger.info("开始处理ComponentVerifyTicket......");
		Document doc = XmlParser.str2Xml(new StringReader(decrypt));
		Element rootElement = doc.getRootElement();
		List<Element> elements = rootElement.selectNodes("/xml/*");
		Map<String, String> ticketInfo = new HashMap<String, String>();
		for (Element e : elements) {
			ticketInfo.put(e.getName(), e.getTextTrim());
		}
		logger.info("ComponentVerifyTicket信息：{}。", ticketInfo);
		ComponentVerifyTicket cvt = new ComponentVerifyTicket();
		cvt.setAppId(ticketInfo.get("AppId"));
		cvt.setComponentVerifyTicket(ticketInfo.get("ComponentVerifyTicket"));
		cvt.setCreateTime(ticketInfo.get("CreateTime"));
		cvt.setInfoType(ticketInfo.get("InfoType"));
		ComponentAccessTokenObservable cato = getContext().getServiceUtil()
				.getService(ComponentAccessTokenObservable.class);
		logger.info("通知监听者刷新Token......");
		cato.refreshToken(cvt);
		logger.info("监听者刷新Token完成。");
		long t2 = System.currentTimeMillis();
		logger.info("处理ComponentVerifyTicket完成，耗时：{}毫秒。", (t2 - t1));
	}
}
